import 'package:intl/intl.dart';

class AppDateUtils {
  static const String defaultDateFormat = 'yyyy-MM-dd';
  static const String defaultTimeFormat = 'HH:mm:ss';
  static const String defaultDateTimeFormat = 'yyyy-MM-dd HH:mm:ss';
  static const String chineseDateFormat = 'yyyy年MM月dd日';
  static const String chineseTimeFormat = 'HH时mm分ss秒';
  static const String chineseDateTimeFormat = 'yyyy年MM月dd日 HH时mm分';
  static const String monthDayFormat = 'MM-dd';
  static const String yearMonthFormat = 'yyyy-MM';
  static const String iso8601Format = 'yyyy-MM-ddTHH:mm:ss.SSSZ';

  static String formatDate(DateTime dateTime, [String format = defaultDateFormat]) {
    return DateFormat(format).format(dateTime);
  }

  static String formatTime(DateTime dateTime, [String format = defaultTimeFormat]) {
    return DateFormat(format).format(dateTime);
  }

  static String formatDateTime(DateTime dateTime, [String format = defaultDateTimeFormat]) {
    return DateFormat(format).format(dateTime);
  }

  static String formatToISO8601(DateTime dateTime) {
    return DateFormat(iso8601Format).format(dateTime);
  }

  static DateTime? parseDate(String dateString, [String format = defaultDateFormat]) {
    try {
      return DateFormat(format).parse(dateString);
    } catch (e) {
      return null;
    }
  }

  static DateTime? parseDateTime(String dateTimeString, [String format = defaultDateTimeFormat]) {
    try {
      return DateFormat(format).parse(dateTimeString);
    } catch (e) {
      return null;
    }
  }

  static DateTime? parseISO8601(String dateTimeString) {
    try {
      return DateTime.parse(dateTimeString);
    } catch (e) {
      return null;
    }
  }

  static String getCurrentDate([String format = defaultDateFormat]) {
    return formatDate(DateTime.now(), format);
  }

  static String getCurrentTime([String format = defaultTimeFormat]) {
    return formatTime(DateTime.now(), format);
  }

  static String getCurrentDateTime([String format = defaultDateTimeFormat]) {
    return formatDateTime(DateTime.now(), format);
  }

  static String getYesterday([String format = defaultDateFormat]) {
    final yesterday = DateTime.now().subtract(const Duration(days: 1));
    return formatDate(yesterday, format);
  }

  static String getTomorrow([String format = defaultDateFormat]) {
    final tomorrow = DateTime.now().add(const Duration(days: 1));
    return formatDate(tomorrow, format);
  }

  static String getRelativeTimeString(DateTime dateTime) {
    final now = DateTime.now();
    final difference = now.difference(dateTime);

    if (difference.inDays > 0) {
      if (difference.inDays == 1) {
        return '1天前';
      } else if (difference.inDays < 7) {
        return '${difference.inDays}天前';
      } else if (difference.inDays < 30) {
        final weeks = (difference.inDays / 7).floor();
        return '${weeks}周前';
      } else if (difference.inDays < 365) {
        final months = (difference.inDays / 30).floor();
        return '${months}个月前';
      } else {
        final years = (difference.inDays / 365).floor();
        return '${years}年前';
      }
    } else if (difference.inHours > 0) {
      return '${difference.inHours}小时前';
    } else if (difference.inMinutes > 0) {
      return '${difference.inMinutes}分钟前';
    } else {
      return '刚刚';
    }
  }

  static bool isToday(DateTime dateTime) {
    final now = DateTime.now();
    return dateTime.year == now.year &&
        dateTime.month == now.month &&
        dateTime.day == now.day;
  }

  static bool isYesterday(DateTime dateTime) {
    final yesterday = DateTime.now().subtract(const Duration(days: 1));
    return dateTime.year == yesterday.year &&
        dateTime.month == yesterday.month &&
        dateTime.day == yesterday.day;
  }

  static bool isTomorrow(DateTime dateTime) {
    final tomorrow = DateTime.now().add(const Duration(days: 1));
    return dateTime.year == tomorrow.year &&
        dateTime.month == tomorrow.month &&
        dateTime.day == tomorrow.day;
  }

  static bool isThisWeek(DateTime dateTime) {
    final now = DateTime.now();
    final weekday = now.weekday;
    final startOfWeek = now.subtract(Duration(days: weekday - 1));
    final endOfWeek = startOfWeek.add(const Duration(days: 6));
    
    return dateTime.isAfter(startOfWeek.subtract(const Duration(days: 1))) &&
        dateTime.isBefore(endOfWeek.add(const Duration(days: 1)));
  }

  static bool isThisMonth(DateTime dateTime) {
    final now = DateTime.now();
    return dateTime.year == now.year && dateTime.month == now.month;
  }

  static bool isThisYear(DateTime dateTime) {
    final now = DateTime.now();
    return dateTime.year == now.year;
  }

  static int daysBetween(DateTime from, DateTime to) {
    from = DateTime(from.year, from.month, from.day);
    to = DateTime(to.year, to.month, to.day);
    return (to.difference(from).inHours / 24).round();
  }

  static List<DateTime> getAllDaysInMonth(int year, int month) {
    final firstDay = DateTime(year, month, 1);
    final lastDay = DateTime(year, month + 1, 0);
    final days = <DateTime>[];
    
    for (int i = 0; i < lastDay.day; i++) {
      days.add(firstDay.add(Duration(days: i)));
    }
    
    return days;
  }

  static DateTime getFirstDayOfMonth(DateTime dateTime) {
    return DateTime(dateTime.year, dateTime.month, 1);
  }

  static DateTime getLastDayOfMonth(DateTime dateTime) {
    return DateTime(dateTime.year, dateTime.month + 1, 0);
  }

  static DateTime getFirstDayOfWeek(DateTime dateTime) {
    final weekday = dateTime.weekday;
    return dateTime.subtract(Duration(days: weekday - 1));
  }

  static DateTime getLastDayOfWeek(DateTime dateTime) {
    final weekday = dateTime.weekday;
    return dateTime.add(Duration(days: 7 - weekday));
  }

  static int getWeekOfYear(DateTime dateTime) {
    final firstDayOfYear = DateTime(dateTime.year, 1, 1);
    final dayOfYear = dateTime.difference(firstDayOfYear).inDays + 1;
    return ((dayOfYear - dateTime.weekday + 10) / 7).floor();
  }

  static String getWeekdayName(int weekday, [bool isShort = false]) {
    const weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
    const shortWeekdays = ['一', '二', '三', '四', '五', '六', '日'];
    
    if (weekday < 1 || weekday > 7) return '';
    
    return isShort ? shortWeekdays[weekday - 1] : weekdays[weekday - 1];
  }

  static String getMonthName(int month, [bool isShort = false]) {
    const months = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
    const shortMonths = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
    
    if (month < 1 || month > 12) return '';
    
    return isShort ? shortMonths[month - 1] : months[month - 1];
  }

  static bool isLeapYear(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
  }

  static int getDaysInMonth(int year, int month) {
    const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    if (month == 2 && isLeapYear(year)) {
      return 29;
    }
    return daysInMonth[month - 1];
  }

  static DateTime addBusinessDays(DateTime dateTime, int days) {
    var result = dateTime;
    var remainingDays = days;
    
    while (remainingDays > 0) {
      result = result.add(const Duration(days: 1));
      if (result.weekday <= 5) {  // 周一到周五
        remainingDays--;
      }
    }
    
    return result;
  }

  static int getBusinessDaysBetween(DateTime from, DateTime to) {
    if (from.isAfter(to)) {
      return -getBusinessDaysBetween(to, from);
    }
    
    var count = 0;
    var current = from;
    
    while (current.isBefore(to)) {
      current = current.add(const Duration(days: 1));
      if (current.weekday <= 5) {  // 周一到周五
        count++;
      }
    }
    
    return count;
  }

  static bool isBusinessDay(DateTime dateTime) {
    return dateTime.weekday <= 5;  // 周一到周五
  }

  static bool isWeekend(DateTime dateTime) {
    return dateTime.weekday > 5;  // 周六和周日
  }

  static DateTime getNextBusinessDay(DateTime dateTime) {
    var result = dateTime.add(const Duration(days: 1));
    while (!isBusinessDay(result)) {
      result = result.add(const Duration(days: 1));
    }
    return result;
  }

  static DateTime getPreviousBusinessDay(DateTime dateTime) {
    var result = dateTime.subtract(const Duration(days: 1));
    while (!isBusinessDay(result)) {
      result = result.subtract(const Duration(days: 1));
    }
    return result;
  }
}